package org.example.time.util;

import java.time.*;
import java.time.format.DateTimeFormatter;
import java.time.temporal.TemporalAccessor;
import java.util.Comparator;
import java.util.Date;

/**
 * 时间日期工具
 * <p>
 * 返回 LocalDate 格式的日、周、月、季度、年起止时间
 *
 * @author Yunkai Luo
 **/
public class LocalDateUtil {

    public static final Comparator<LocalDate> LOCAL_DATE_COMPARATOR = (t1, t2) -> {
        if (t1 == null) {
            return -1;
        } else if (t2 == null) {
            return 1;
        }

        if (t1.isBefore(t2)) {
            return -1;
        } else if (t2.isBefore(t1)) {
            return 1;
        }

        return 0;
    };

    /**
     * @Description:当天的开始时间
     * @Param: [today, isFirst: true 表示开始时间，false表示结束时间]
     */
    public static LocalDate getStartOrEndDayOfDay(LocalDate today, Boolean isFirst) {
        LocalDate resDate = LocalDate.now();
        if (today == null) {
            today = resDate;
        }
        if (isFirst) {
            return today;
        } else {
            return today;
        }
    }

    /**
     * @Description:本周的开始时间
     * @Param: [today, isFirst: true 表示开始时间，false表示结束时间]
     */
    public static LocalDate getStartOrEndDayOfWeek(LocalDate today, Boolean isFirst) {
        LocalDate resDate = LocalDate.now();
        if (today == null) {
            today = resDate;
        }
        DayOfWeek week = today.getDayOfWeek();
        int value = week.getValue();
        if (isFirst) {
            resDate = today.minusDays(value - 1);
        } else {
            resDate = today.plusDays(7 - value);
        }
        return resDate;
    }

    /**
     * @return
     * @Description:本月的开始时间
     * @Param: [today, isFirst: true 表示开始时间，false表示结束时间]
     */
    public static LocalDate getStartOrEndDayOfMonth(LocalDate today, Boolean isFirst) {
        LocalDate resDate = LocalDate.now();
        if (today == null) {
            today = resDate;
        }
        Month month = today.getMonth();
        int length = month.length(today.isLeapYear());
        if (isFirst) {
            resDate = LocalDate.of(today.getYear(), month, 1);
        } else {
            resDate = LocalDate.of(today.getYear(), month, length);
        }
        return resDate;
    }

    /**
     * @Description:本季度的开始时间
     * @Param: [today, isFirst: true 表示开始时间，false表示结束时间]
     */
    public static LocalDate getStartOrEndDayOfQuarter(LocalDate today, Boolean isFirst) {
        LocalDate resDate = LocalDate.now();
        if (today == null) {
            today = resDate;
        }
        Month month = today.getMonth();
        Month firstMonthOfQuarter = month.firstMonthOfQuarter();
        Month endMonthOfQuarter = Month.of(firstMonthOfQuarter.getValue() + 2);
        if (isFirst) {
            resDate = LocalDate.of(today.getYear(), firstMonthOfQuarter, 1);
        } else {
            resDate = LocalDate.of(today.getYear(), endMonthOfQuarter, endMonthOfQuarter.length(today.isLeapYear()));
        }
        return resDate;
    }

    /**
     * @Description:本年度的开始时间
     * @Param: [today, isFirst: true 表示开始时间，false表示结束时间]
     */
    public static LocalDate getStartOrEndDayOfYear(LocalDate today, Boolean isFirst) {
        LocalDate resDate = LocalDate.now();
        if (today == null) {
            today = resDate;
        }
        if (isFirst) {
            resDate = LocalDate.of(today.getYear(), Month.JANUARY, 1);
        } else {
            resDate = LocalDate.of(today.getYear(), Month.DECEMBER, Month.DECEMBER.length(today.isLeapYear()));
        }
        return resDate;
    }

    /**
     * 从time按指定格式化器格式化
     *
     * @param time 时间
     * @return 时间字符串
     */
    public static String format(TemporalAccessor time) {
        return format(time, DateTimeFormatter.ISO_LOCAL_DATE);
    }

    /**
     * 从time按指定格式化器格式化
     *
     * @param time      时间
     * @param formatter 格式化器
     * @return 时间字符串
     */
    public static String format(TemporalAccessor time, DateTimeFormatter formatter) {
        if (null == time) {
            return null;
        }

        if (null == formatter) {
            formatter = DateTimeFormatter.ISO_LOCAL_DATE;
        }

        return formatter.format(time);
    }

    public static LocalDate deserialize(String date) {
        return LocalDate.parse(date, DateTimeFormatter.ISO_LOCAL_DATE);
    }

    /**
     * 替代 System.currentTimeMillis()
     *
     * @return 时间戳
     */
    public static long currentTimeMillis() {
        Instant instant = LocalDateTime.now().atZone(ZoneId.systemDefault()).toInstant();
        return instant.toEpochMilli();
    }

    public static LocalDate getStartOrEndDayOf(ClassificationOfTimeEnum classificationOfTimeEnum, LocalDate today, boolean isFirst) {
        switch (classificationOfTimeEnum) {
            case DAY:
                return getStartOrEndDayOfDay(today, isFirst);
            case MONTH:
                return getStartOrEndDayOfMonth(today, isFirst);
            case YEAR:
                return getStartOrEndDayOfYear(today, isFirst);
            case WEEK:
                return getStartOrEndDayOfWeek(today, isFirst);
            case QUARTER:
                return getStartOrEndDayOfQuarter(today, isFirst);
            case HOUR:
            case MINUTE:
            case SECOND:
                return today;
            default:
                return null;
        }
    }

    public static LocalDate getDate(int days, LocalDate date) {
        return date.plusDays(days);
    }

    public static Date toDate(LocalDate date) {
        ZoneId zone = ZoneId.systemDefault();
        Instant instant = date.atStartOfDay().atZone(zone).toInstant();
        return Date.from(instant);
    }
}
